/**
 *  使用  pnpm run i18n path [token]
 *  eg.   pnpm run i18n web/src/views/demand/annual-dimension VGh1QXByMTMwODozMDowN0NTVDIwMjMjQ0hFTkpJQVhJTkc=@
 *  path为执行路径其根目录为packages token可选（可从header中自行获取）
 */

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const { chalk } = require('@vue/cli-shared-utils');
const { execSync } = require('child_process');

const vueComplierDom = require('@vue/compiler-dom');
const { parse } = require('@babel/parser');
const t = require('@babel/types');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const INOGREFILES = ['print-data.js'];

const CNREG = /[\u4e00-\u9fa5]/;
const matchCN = value => typeof value === 'string' && value.match(CNREG);
const chineseDict = {};
const MISSMATCH = new Set();

//log
const logFile = {
  unMatchChinese: [], // 未匹配中文
  updateFile: [], // 修改文件
  updateFileRecord: [],
  addUpdate(file, str) {
    this.updateFile.push(file);
    this.updateFileRecord.push(`${file} -------- ${str}`);
  }
};

const log = {
  info(msg) {
    console.log(chalk.green(msg));
  },
  error(msg) {
    console.log(chalk.red(msg));
  },
  warnning(msg) {
    console.log(chalk.yellow(msg));
  }
};

const notMatch = (msg, file) => {
  msg.length < 50 && MISSMATCH.add(msg.trim());
  !checkMode && console.log(chalk.red(`[${chalk.yellow(msg)}] 未找到对应的词条`, chalk.yellow(file)));
  logFile.unMatchChinese.push(msg); // 未匹配中文
};

async function writeArrayText(arrText, fileName) {
  const text = [...new Set(arrText)].join('\n');
  await fs.writeFileSync(fileName, text, {
    encoding: 'utf-8'
  });
}

// 获取文件列表
function getFileListForPath(filepath) {
  const list = fs.readdirSync(filepath, {
    encoding: 'utf-8'
  });
  return list.map(item => {
    const itemPath = `${filepath}/${item}`;
    const isFile = fs.statSync(itemPath).isFile();
    return isFile ? itemPath : getFileListForPath(itemPath);
  });
}

// 所有文件夹下获取到的Vue、js文件
function getFiles(filepath) {
  const isFile = fs.statSync(filepath).isFile();
  if (isFile) {
    return [filepath];
  }
  const files = getFileListForPath(filepath);
  return files.flat(Infinity).filter(pathItem => {
    return (
      !INOGREFILES.includes(path.basename(pathItem)) &&
      path.normalize(pathItem).indexOf('\\src\\views') > -1 &&
      ['.js', '.vue'].includes(path.extname(pathItem))
    );
  });
}

// 获取字典

async function getDict(Authorization) {
  // 创建axios实例
  const service = axios.create({
    baseURL: 'http://webcloudtest.byd.com.cn/icloudNew/api/',
    timeout: 60000,
    headers: {
      'Cache-Control': 'no-cache',
      Authorization
    }
  });

  const {
    data: { data }
  } = await service.get(`/msp-admin/lang/list?langType=zh-CN`); // 中文配置
  // eslint-disable-next-line guard-for-in
  for (const key in data) {
    chineseDict[data[key]] = key;
  }
}

const patchTemplate = (ast, file) => {
  const result = {
    props: [],
    contents: []
  };

  let str = ast.loc.source;

  const traverseNode = node => {
    const { type, content, props } = node;
    if (type === 1) {
      props.forEach(prop => {
        const propValue = prop.value && prop.value.content;

        if (matchCN(propValue)) {
          result.props.push({
            label: prop.name,
            value: prop.value.content
          });
        }
      });
    }
    if (type === 2 && matchCN(content)) {
      result.contents.push(content);
    }

    if (node.children) {
      node.children.forEach(item => traverseNode(item));
    }
  };

  traverseNode(ast);

  result.props.forEach(prop => {
    const string = `${prop.label}="${prop.value}"`;
    let i18nstr = prop.value.trim();
    const hasSuffix = i18nstr.match(/(:|：)$/);
    const suffix = i18nstr[i18nstr.length - 1];
    if (hasSuffix) {
      i18nstr = i18nstr.slice(0, -1);
    }
    if (chineseDict[i18nstr]) {
      str = str.replace(string, `:${prop.label}="$t('${chineseDict[i18nstr]}')${hasSuffix ? ` + '${suffix}'` : ''}"`);
    } else {
      notMatch(prop.value, file);
    }
    logFile.addUpdate(file, i18nstr);
  });
  result.contents.forEach(ct => {
    let i18nstr = ct.trim();
    const hasSuffix = i18nstr.match(/(:|：)$/);
    const suffix = i18nstr[i18nstr.length - 1];
    if (hasSuffix) {
      i18nstr = i18nstr.slice(0, -1);
    }
    if (chineseDict[i18nstr]) {
      str = str.replace(ct, ` {{ $t('${chineseDict[i18nstr]}') }} ${hasSuffix ? suffix : ''}`);
    } else {
      notMatch(ct, file);
    }
    logFile.addUpdate(file, i18nstr);
  });

  return str;
};

const patchScript = (script, file, js) => {
  const scriptAst = parse(script, {
    sourceType: 'module',
    plugins: ['jsx', 'typescript']
  });

  traverse(scriptAst, {
    StringLiteral(nodePath) {
      if (matchCN(nodePath.node.value)) {
        const trimstr = nodePath.node.value.trim();
        if (chineseDict[trimstr]) {
          nodePath.replaceWith(
            t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('$t')), [
              t.stringLiteral(chineseDict[trimstr])
            ])
          );
        } else {
          notMatch(nodePath.node.value, file);
        }
        logFile.addUpdate(file, trimstr);
      }
    },
    TemplateLiteral(nodePath) {
      const { quasis } = nodePath.node;
      quasis.forEach(quasi => {
        const { value } = quasi;
        if (matchCN(value.raw)) {
          const trimstr = value.raw.trim();
          // console.log('--------------------', value);
          if (chineseDict[trimstr]) {
            value.raw = value.raw.replace(trimstr, `\${this.$t('${chineseDict[trimstr]}')}`);
            value.cooked = value.cooked.replace(trimstr, `\${this.$t('${chineseDict[trimstr]}')}`);
          } else {
            notMatch(trimstr, file, 2);
          }
          logFile.addUpdate(file, trimstr);
        }
      });
    }
  });
  const { code } = generate(scriptAst, {
    retainFunctionParens: true,
    retainLines: true
  });
  return js ? code : `<script>\n${generate(scriptAst).code}\n</script>`;
};

async function start(replacePath = '', Authorization, checkAll) {
  log.info('读取远程国际化资源...');
  await getDict(Authorization);
  const foldPath = path.resolve(__dirname, '../packages', replacePath);
  log.info('读取本地目录...');
  const files = getFiles(foldPath); // replacePath目录下所有vue js 文件

  log.info('开始自动替换...');
  files.forEach(pathItem => {
    // 读取文件

    const file = fs.readFileSync(pathItem, {
      encoding: 'utf-8'
    });
    let newFile = '';
    try {
      if (pathItem.endsWith('.vue')) {
        const ast = vueComplierDom.parse(file);

        newFile = ast.children
          .map(item => {
            if (item.tag === 'template') {
              return patchTemplate(item, pathItem);
            }

            if (item.tag === 'script') {
              return patchScript(item.children[0].content, pathItem);
            }

            return item.loc.source;
          })
          .join('\n');
      } else {
        newFile = patchScript(file, pathItem, true);
      }

      !checkAll && fs.writeFileSync(pathItem, newFile, 'utf8');
    } catch (error) {
      log.error(error);
      log.error(`文件:${pathItem}执行失败。。。`);
    }
  });

  if (!checkAll) {
    log.info('国际化修改完成, 正在格式化代码...');
    // execSync(`npx prettier --write ${foldPath}`);
    const isFile = fs.statSync(foldPath).isFile();
    if (isFile) {
      execSync(`npx eslint ${foldPath} --fix`);
    } else {
      execSync(`npx eslint ${foldPath}/**/* --fix`);
    }
    log.info('完成, 请对本次修改进行人工核对');
  } else {
    log.info('完成, 写日志');
    // 写日志
    if (!fs.existsSync('./log')) {
      fs.mkdirSync('./log');
    }
    writeArrayText(logFile.unMatchChinese, './log/unMatchChinese.txt');
    writeArrayText(logFile.updateFile, './log/file.txt');
    writeArrayText(logFile.updateFileRecord, './log/fileRecord.txt');
    log.info('-------------请查看日志记录-------------');
    // log.info('-----------------------------------------');
    // log.warnning([...MISSMATCH.values()]);
    // fs.writeFileSync('./i18n.txt', [...MISSMATCH.values()].join('\n'));
    // log.info('-----------------------------------------');
  }
}

const checkMode = process.argv.indexOf('--check') > 0;
// console.log(process.argv);
// process.argv.splice(checkMode, 1);
console.log(process.argv, checkMode);
let replacePath = process.argv[2];
let Authorization = process.argv[3];
if (checkMode) {
  replacePath = process.argv[3];
  Authorization = process.argv[4];
}
if (!checkMode && !replacePath) {
  log.error('请输入文件路径');
  log.warnning('   pnpm run i18n path [token]');
} else {
  start(replacePath, Authorization || 'VGh1QXByMTMwODozMDowN0NTVDIwMjMjQ0hFTkpJQVhJTkc=@', checkMode);
}
